package at.fhhagenberg.hydrac.backend.codegenerators.java;

import java.util.List;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class JavaContext {

  private AST ast;

  private CompilationUnit cu;

  private TypeDeclaration classObj;

  private MethodDeclaration currMethod;

  public JavaContext() {
    ast = AST.newAST(AST.JLS4);
    cu = ast.newCompilationUnit();

    classObj = ast.newTypeDeclaration();
    cu.types().add(classObj);
  }

  public AST getAst() {
    return ast;
  }

  public void setProgramName(String name) {
    classObj.setName(ast.newSimpleName(name));
  }

  public void addMainFunction() {
    MethodDeclaration methodDecl = ast.newMethodDeclaration();
    methodDecl.setName(ast.newSimpleName("main"));
    methodDecl.setBody(ast.newBlock());

    List<Modifier> modifiers = methodDecl.modifiers();
    modifiers.add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
    modifiers.add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));

    SingleVariableDeclaration varDecl = ast.newSingleVariableDeclaration();
    varDecl.setType(ast.newArrayType(ast.newSimpleType(ast.newName("String"))));
    varDecl.setName(ast.newSimpleName("args"));
    methodDecl.parameters().add(varDecl);

    classObj.bodyDeclarations().add(methodDecl);
    currMethod = methodDecl;
  }

  public void show() {
    System.out.println(cu.toString());
  }

  public void addVariable(String type, String name) {
    VariableDeclarationFragment varDecl = ast.newVariableDeclarationFragment();
    varDecl.setName(ast.newSimpleName(name));
    varDecl.setExtraDimensions(0);

    VariableDeclarationStatement varDecltStmt = ast.newVariableDeclarationStatement(varDecl);
    varDecltStmt.setType(getType(type));

    addStatement(varDecltStmt);

  }

  private Type getType(String type) {
    switch (type.toLowerCase()) {
    case "int":
      return ast.newPrimitiveType(PrimitiveType.INT);
    case "string":
      return ast.newSimpleType(ast.newName("String"));
    }
    return null;
  }

  void addStatement(Statement stmt) {
    currMethod.getBody().statements().add(stmt);
  }

}
